#include "../include/_static.hpp"


struct Impl_Static{
    std::string File_path;  // 文件路径
    std::string url;  // 媒体其实路径
    Impl_Static(std::string file_path,std::string url):File_path(file_path),url(url){}
    Impl_Static(){}
};

std::unordered_map<std::string,std::string> static_types;  // 定义

void configurationStaticType(){
    static_types.insert(std::pair<std::string,std::string>("css","text/css"));
    static_types.insert(std::pair<std::string,std::string>("js","text/javascript"));
    static_types.insert(std::pair<std::string,std::string>("jpg","image/jpeg"));
    static_types.insert(std::pair<std::string,std::string>("html","text/html"));
    static_types.insert(std::pair<std::string,std::string>("woff2","font/woff2"));
    static_types.insert(std::pair<std::string,std::string>("png","image/png"));
    static_types.insert(std::pair<std::string,std::string>("gif","image/gif"));
    static_types.insert(std::pair<std::string,std::string>("jpeg","image/jpeg"));
    static_types.insert(std::pair<std::string,std::string>("mp4","video/mp4"));
    // media_types.insert(std::pair<std::string,std::string>("gif","image/gif"));
}

_Static::_Static(){
    pimpl=std::shared_ptr<Impl_Static>(new(std::nothrow) Impl_Static());
}
_Static::_Static(std::string file_path,std::string url){
    pimpl=std::shared_ptr<Impl_Static>(new(std::nothrow) Impl_Static(file_path,url));
}
int _Static::is_exist(std::string path,int& file_size){ // 判断媒体文件是否存在 存在返回 0 不存在返回 -1
    struct stat buffer;
    std::string p=pimpl->File_path+path;
    if(stat(p.c_str(),&buffer)==0){
        file_size=buffer.st_size;
        return 0;
    }
    return -1;

}

void _Static::url(std::string url,std::string file_path){
    pimpl->File_path=file_path;
    pimpl->url=url;
}

std::string _Static::get_filePath(){
    return pimpl->File_path;
}

_Static Static;




std::shared_ptr<Response> ResponseStaticFile(HTTP* args){
    std::shared_ptr<Response> resp(new Response(args->get_ReqHead()));
    std::string buf("404");
    std::string dirs;

    if(args->get_ReqHead()->getUrlParams().size()<=1){

        resp->setText(buf);
        resp->setStatus(404);
        resp->setDescribe("ERR");
        return resp;
    }
    dirs=args->get_ReqHead()->getUrlParams()[1];

    int file_size;
    if(Static.is_exist(dirs,file_size)<0){
        resp->setText(buf);
        resp->setStatus(404);
        resp->setDescribe("ERR");
        return resp;
    }else{
        if(args->get_ReqHead()->getHeaders().find("Range")==args->get_ReqHead()->getHeaders().end()){
            resp->setStatus(200);
            resp->setDescribe("succes");
            std::string tpe;
            tpe=dirs.substr(dirs.find_last_of('.') + 1);//获取文件后缀
            resp->setMsg("Content-Type",static_types[tpe]);
            resp->setMsg("Connection","keep-alive");
            // resp->setMsg("Transfer-Encoding","chunked");
            resp->setMsg("Accept-Ranges","bytes");
            resp->setMsg("Content-Length",std::to_string(file_size));
            resp->setMsg("Set-Cookie","start=0");
            if(tpe.compare("mp4")!=0){
                std::string value=resp->returnResponse();
                int r=write(args->client_fd,value.c_str(),value.size());
                if(r==-1){
                    resp->setClose(1);
                    resp->setSend(1);
                    return resp;
                }
                std::string path=Static.get_filePath()+dirs;
                std::shared_ptr<FILE> file(fopen(path.c_str(),"r"));
                if(file==nullptr){
                    
                    DBGprint("文件打开失败\n");
                    resp->setClose(1);
                    resp->setSend(1);
                    return resp;
                }
                int read_len=0;
                char buf[2048];
                int w;
                while((read_len=fread(buf,sizeof(char),2048,file.get()))!=0){
                    w=write(args->client_fd,buf,read_len);
                    if(w==-1 || read_len==0){
                        break;
                    }
                }

                resp->setClose(1);
                resp->setSend(1);
                return resp;
            }
            return resp;
        }
        resp->setStatus(206);
        resp->setDescribe("Partial Content");        
        std::string tpe;
        tpe=dirs.substr(dirs.find_last_of('.') + 1);//获取文件后缀
        resp->setMsg("Content-Type",static_types[tpe]);
        resp->setMsg("Connection","keep-alive");
        resp->setMsg("Transfer-Encoding","chunked");
        resp->setMsg("Accept-Ranges","bytes");
        
        std::string Range=args->get_ReqHead()->getHeaders().at("Range");
        int _a=Range.find_last_of("=");
        int _b=Range.find_last_of("-");
        std::string range_a=Range.substr(_a+1,_b-_a-1);
        std::string range_b=Range.substr(_b+1);
        int range_1=std::atoi(range_a.c_str());
        int range_2=0;
        
        if(range_b.empty()){
            range_2=std::min(range_1+1024*1024*5,file_size-1); //std::min(file_size-range_1,1024*1024*4);
        }

        if(range_1>file_size ){
            resp->setText(buf);
            resp->setStatus(416);
            resp->setDescribe("ERR");
            return resp;
        }
        // resp->setMsg("Content-Length",std::to_string(range_2));
        std:: ostringstream ss;
        ss<<"bytes "<<range_a<<"-"<<range_2<<"/"<<file_size;
        resp->setMsg("Content-Range",ss.str());
        std::string value=resp->returnResponse();
        int r=write(args->client_fd,value.c_str(),value.size());
        if(r==-1 || r==0){
            DBGprint("响应未能发送\n");
            resp->setClose(1);
            resp->setSend(1);
            return resp;
        }
        std::string path=Static.get_filePath()+dirs;
        
        std::shared_ptr<FILE> file(fopen(path.c_str(),"r"));
        if(file==NULL){
            DBGprint("文件打开失败\n");
            resp->setClose(1);
            resp->setSend(1);
            return resp;
        }
        int read_len=0;
        char buf[2048];
        std::ostringstream sss;
        sss<<std::hex<<file_size<<"\r\n";
        std::string ttt=sss.str();
        int w;

        w=write(args->client_fd,ttt.c_str(),ttt.size());
        if(r==-1 || r==0){
            DBGprint("开始符未能发送\n");
            resp->setClose(1);
            resp->setSend(1);
            return resp;
        }
        if(range_1>=0){
            fseek(file.get(),range_1,SEEK_SET);
        }else{
            fseek(file.get(),range_1,SEEK_END);
        }
        int sum=range_2-range_1;
        while(sum>0){
            read_len=fread(buf,sizeof(char),std::min(2048,sum),file.get());
            sum=sum-read_len;
            w=write(args->client_fd,buf,read_len);
            if(w==-1 || read_len==0){
                std::cout<<errno<<" "<<strerror(errno)<<std::endl;
                DBGprint("连接终止\n");
                break;
            }

        }

        w=write(args->client_fd,"\r\n0\r\n\r\n",7);
        if(w==-1){
            DBGprint("结束符未能发送\n");
        }
        resp->setClose(1);
        resp->setSend(1);
        return resp;
        
        
    }

    
    
    return resp;
}

